﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UMD.HCIL.Piccolo;
using System.Drawing;

namespace TreeMap.Graphics
{
	public class GraphicsManager
	{
		#region singleton stuff
		private static GraphicsManager MyInstance = new GraphicsManager();

		public static GraphicsManager GetInstance
		{
			get
			{
				return MyInstance;
			}
		}

		private GraphicsManager()
		{
		}
		#endregion

		public int Granularity { get; set; }
		public PCanvas Canvas { get; set; }

		private Point RootStartPoint = new Point(0, 0);
		private Point RootEndPoint;

		private EntryNode CurrentParentNode;
		private static Random RandomManager = new Random();
		private Dictionary<string, Brush> ColorManager = new Dictionary<string, Brush>();
		private int Balance = 0;

		/// <summary>
		/// Dictionary that hold all Nodes to draw
		/// </summary>
		private Dictionary<EntryNode, GraphicsNode> MyDictionaryToDraw = new Dictionary<EntryNode, GraphicsNode>();

		/// <summary>
		/// HERE all the drawing action happens
		/// </summary>
		/// <param name="canvas"></param>
		public void Draw(PCanvas canvas)
		{
			//Setting canvas
			Canvas = canvas;

			//Drawing all the nodes
			DrawNodes(EntryManager.Instance.RootNodes, false);
		}

		private void DrawNodes(List<EntryNode> listOfNodes, bool root)
		{
			this.MyDictionaryToDraw.Clear();
			Canvas.Layer.RemoveAllChildren();
			RootStartPoint.X = 0;
			RootStartPoint.Y = 0;
			RootEndPoint.X = 0;
			RootEndPoint.Y = 0;

			foreach (EntryNode EntryNode in listOfNodes)
			{
				RootStartPoint = new Point(RootEndPoint.X, 0);
				RootEndPoint = new Point((int)(Canvas.Width * EntryNode.Importance) + RootStartPoint.X, (Canvas.Height));

				ShowNode(EntryNode, 1, root);
			}
		}

		/// <summary>
		/// Display the graphics nodes
		/// </summary>
		/// <param name="EntryNode"></param>
		private void ShowNode(EntryNode EntryNode, int granularity, bool root)
		{
			//Add to dictionary
			if (!this.MyDictionaryToDraw.ContainsKey(EntryNode))
			{
				this.MyDictionaryToDraw.Add(EntryNode, new GraphicsNode(EntryNode.Value, Canvas));
			}


			if (granularity <= Granularity)
			{
				//For root nodes
				if (EntryNode.Parent == null || root)
				{
					this.MyDictionaryToDraw[EntryNode].TopLeft = RootStartPoint;
					this.MyDictionaryToDraw[EntryNode].BottomRight = RootEndPoint;
					//this.MyDictionaryToDraw[EntryNode].NextStartPoint = RootStartPoint; //Speichern des Startpunktes für das nächste Geschwisterelement
					this.MyDictionaryToDraw[EntryNode].NextStartPoint = new Point(RootStartPoint.X + 15, RootStartPoint.Y + 15);
					this.MyDictionaryToDraw[EntryNode].Horizontal = false;

				}
				else
				{
					//Setzen des Elternknoten, dessen Child gerade bearbeitet wird
					CurrentParentNode = EntryNode.Parent;
					Balance = 15 / EntryNode.Parent.Children.Count;

					//Wenn der Parent Node nicht horizontal gezeichnet wurde, dann soll der ChildNode horizontal gezeichnet werden
					if (!this.MyDictionaryToDraw[EntryNode.Parent].Horizontal)
					{
						//Do some action here
						this.MyDictionaryToDraw[EntryNode].TopLeft = this.MyDictionaryToDraw[EntryNode.Parent].NextStartPoint;
						this.MyDictionaryToDraw[EntryNode].BottomRight = new Point((int)this.MyDictionaryToDraw[EntryNode.Parent].BottomRight.X, (int)(((this.MyDictionaryToDraw[EntryNode.Parent].BottomRight.Y - this.MyDictionaryToDraw[EntryNode.Parent].TopLeft.Y) * EntryNode.Importance) + this.MyDictionaryToDraw[EntryNode].TopLeft.Y) - Balance);
						this.MyDictionaryToDraw[EntryNode.Parent].NextStartPoint = new Point(this.MyDictionaryToDraw[EntryNode].TopLeft.X, (int)this.MyDictionaryToDraw[EntryNode].BottomRight.Y); //Speichern des Startpunktes für das nächste Geschwisterelement
						this.MyDictionaryToDraw[EntryNode].Horizontal = !this.MyDictionaryToDraw[EntryNode.Parent].Horizontal;

						//Speichern des eigenen StartPoint
						//this.MyDictionaryToDraw[EntryNode].NextStartPoint = this.MyDictionaryToDraw[EntryNode].TopLeft;
						this.MyDictionaryToDraw[EntryNode].NextStartPoint = new Point(this.MyDictionaryToDraw[EntryNode].TopLeft.X + 15, this.MyDictionaryToDraw[EntryNode].TopLeft.Y + 15);
					}
					else
					{
						//Do some action here 
						this.MyDictionaryToDraw[EntryNode].TopLeft = this.MyDictionaryToDraw[EntryNode.Parent].NextStartPoint;
						this.MyDictionaryToDraw[EntryNode].BottomRight = new Point((int)(((this.MyDictionaryToDraw[EntryNode.Parent].BottomRight.X - this.MyDictionaryToDraw[EntryNode.Parent].TopLeft.X) * EntryNode.Importance) + this.MyDictionaryToDraw[EntryNode].TopLeft.X) - Balance, (int)this.MyDictionaryToDraw[EntryNode.Parent].BottomRight.Y);
						this.MyDictionaryToDraw[EntryNode.Parent].NextStartPoint = new Point(this.MyDictionaryToDraw[EntryNode].BottomRight.X, this.MyDictionaryToDraw[EntryNode].TopLeft.Y);//Speichern des Startpunktes für das nächste Geschwisterelement
						this.MyDictionaryToDraw[EntryNode].Horizontal = !this.MyDictionaryToDraw[EntryNode.Parent].Horizontal;

						//Speichern des eigenen StartPoint
						//this.MyDictionaryToDraw[EntryNode].NextStartPoint = this.MyDictionaryToDraw[EntryNode].TopLeft;
						this.MyDictionaryToDraw[EntryNode].NextStartPoint = new Point(this.MyDictionaryToDraw[EntryNode].TopLeft.X + 15, this.MyDictionaryToDraw[EntryNode].TopLeft.Y + 15);
					}
				}

				if (granularity == Granularity || EntryNode.Children.Count == 0)
				{
					if (ColorManager.ContainsKey(EntryNode.Value))
					{
						this.MyDictionaryToDraw[EntryNode].Brush = ColorManager[EntryNode.Value];
					}
					else
					{
						this.MyDictionaryToDraw[EntryNode].Brush = CalulateBrush();
						ColorManager.Add(EntryNode.Value, this.MyDictionaryToDraw[EntryNode].Brush);
					}
					//this.MyDictionaryToDraw[EntryNode].CalulateBrush();
				}

				//Zeichnen des Nodes
				this.MyDictionaryToDraw[EntryNode].Draw();
			}


			//Call recursion
			foreach (EntryNode ChildNode in EntryNode.Children)
			{
				ShowNode(ChildNode, granularity + 1, false);
			}

		}

		/// <summary>
		/// Calculates Brush of an Node - used for last shown category
		/// </summary>
		public System.Drawing.Brush CalulateBrush()
		{
			int red = RandomManager.Next(0, byte.MaxValue + 1);
			int green = RandomManager.Next(0, byte.MaxValue + 1);
			int blue = RandomManager.Next(0, byte.MaxValue + 1);
			return new System.Drawing.SolidBrush(Color.FromArgb(red, green, blue));
		}

		/// <summary>
		/// Is called, when user clicks on one box
		/// </summary>
		/// <param name="graphicsNode"></param>
		internal void ShowClickedBoxOnly(GraphicsNode graphicsNode)
		{
			try
			{
				//Auslesen des KeyValue Pairs, auf dessen GraphicsNode geklickt wurde
				KeyValuePair<EntryNode, GraphicsNode> ClickedNode = MyDictionaryToDraw.FirstOrDefault(d => d.Value == graphicsNode);

				//Nur wenn der geklickte Knoten auch Kinder hat, dann sollen diese angezeigt werden
				if (ClickedNode.Key.Children.Count > 0)
				{
					DrawNodes(ClickedNode.Key.Children, true);
				}
			}
			catch (Exception)
			{
			}
		}
	}
}
